package cn.buk.tms.flight.service;

import cn.buk.api.szkj.dto.eterm.response.RtpnrResponse;
import cn.buk.common.JsonResult;
import cn.buk.tms.entity.misc.EntDepartment;
import cn.buk.tms.entity.order.flight.FlightOrder;
import cn.buk.qms.service.BaseFlightOrderService;
import cn.buk.qms.service.FlightOrderService;
import cn.buk.tms.common.constant.TmsOrderConstant;
import cn.buk.tms.flight.util.FlightOrderUtil;
import cn.buk.common.util.DateUtil;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;

import static cn.buk.tms.entity.config.EnterpriseConfig.TMS_AUTO_TICKET_MODE;
import static cn.buk.tms.common.constant.TmsConstant.*;
import static cn.buk.tms.common.constant.TmsOrderConstant.*;

/**
 * @author yfdai
 */
@Service
public class AutoTicketServiceImpl extends BaseFlightOrderService implements AutoTicketService {

  public static final Logger logger = LogManager.getLogger(AutoTicketServiceImpl.class);



  @Autowired
  public AutoTicketServiceImpl(
          EtermService etermService,
          AutoTicketBspEtermWorker autoTicketBspEtermWorker,
          AutoTicketBspSzkjWorker autoTicketBspSzkjWorker,
          AutoTicketGpWorker autoTicketGpWorker,
          AutoTicketCzNdcWorker czNdcWorker,
          FlightOrderService flightOrderService
  ) {
    this.etermService = etermService;
    this.etermWorker = autoTicketBspEtermWorker;
    this.szkjWorker = autoTicketBspSzkjWorker;
    this.gpWorker = autoTicketGpWorker;
    this.czNdcWorker = czNdcWorker;
    this.flightOrderService = flightOrderService;
  }

  private final EtermService etermService;

  private final AutoTicketBspEtermWorker etermWorker;

  private final AutoTicketBspSzkjWorker szkjWorker;

  private final AutoTicketGpWorker gpWorker;

  private final AutoTicketCzNdcWorker czNdcWorker;

  private final FlightOrderService flightOrderService;


  @Override
  public void checkAutoTicketOrder(final int enterpriseId, final String username) {
    //自动开票方式：BSP，接口
    final int etermApiType = doGetEntCfg(enterpriseId, TMS_AUTO_TICKET_MODE, 0);

    if (etermApiType == ETERM_API_DISABLED) {
      //停用自动开票
      return;
    }

    //搜索订单生成日期大于指定日期的，待认领和已认领出票的订单(有些订单会提前创建好，过几天再提交出票）
    final Date startDate = DateUtil.addDays(DateUtil.getCurDate(), -10);
    List<FlightOrder> flightOrders = flightOrderDao.searchWaitingForAutoTicketOrder(enterpriseId, startDate);

    if (flightOrders.isEmpty()) {
      return;
    }

    logger.info("waiting for issuing ticket: {}" , flightOrders.size());

    for (FlightOrder flightOrder : flightOrders) {
      FlightOrder orderInfo = flightOrderDao.getOrderDetailById(flightOrder.getId());

      if (!isValidToAutoTicketing(orderInfo)) {
        //不符合自动开票的条件
        continue;
      }

      try {
        int orderChanged = prepareFlightOrder(enterpriseId, username, orderInfo);
        if (orderChanged == 1) {
          //刷新订单内容
          orderInfo = flightOrderDao.getOrderDetailById(flightOrder.getId());
        }

        int retCode = execAutoTicketOrder(enterpriseId, username, orderInfo, etermApiType, orderInfo.getSupplier().getIsBsp());
        logger.info("{}, {}, {}: {}", orderInfo.getOrderNo(), etermApiType, orderInfo.getSupplier().getIsBsp(), retCode);
      } catch (Exception ex) {
        ex.printStackTrace();
      }
    }
  }

  /**
   * 为CZ NDC开票预处理订单
   * @param orderInfo 订单详情
   * @return 0 - 订单内容未更新，1 - 订单内容更新
   */
  private int prepareFlightOrder(final int enterpriseId, final String username, final FlightOrder orderInfo) {
    //非单程暂时不处理
    if (orderInfo.getFlights().size() != 1) {
      return 0;
    }

    //非CZ的，不处理
    if (!AIRLINE_CZ_CODE.equalsIgnoreCase(orderInfo.getFlights().get(0).getCarrierCode())) {
      return 0;
    }

    //判断当前订单是否有 STOP标志
    final String orderStopKey = String.format(CZ_NDC_ORDER_KEY, enterpriseId, orderInfo.getOrderNo());
    boolean orderStopKeyExisted = redisDao.exists(orderStopKey);
    logger.info("{}: {}", orderStopKey, orderStopKeyExisted);

    //存在该key，表明上次有CZ NDC订单支付失败，暂不执行CZ NDC开票
    final String key = String.format(CZ_NDC_AMOUNT_BALANCE, enterpriseId);
    boolean keyExisted = redisDao.exists(key);
    logger.info("{}: {}", key, keyExisted);

    if (keyExisted || orderStopKeyExisted) {
      if (orderInfo.getSupplier().getIsBsp() == FLIGHT_AUTO_TICKETING_NDC_CZ) {
        flightOrderService.updateFlightOrderSupplierType(enterpriseId, username, orderInfo.getId(), FLIGHT_AUTO_TICKETING_BSP);
        logger.info( "{}: NDC_CZ -> BSP", orderInfo.getOrderNo());
        return 1;
      } else {
        return 0;
      }
    }

    //机票订单的创建时间和客服提交开票的时间应该有差距
    final int m = DateUtil.getPastMinutes(orderInfo.getSubmitTime() == null ? orderInfo.getCreateTime() : orderInfo.getSubmitTime());
    if (m <= 5) {
      doSendAlert(enterpriseId, "CZ: " + orderInfo.getOrderNo(), null, EntDepartment.DEPT_TICKETING);

      if (orderInfo.getSupplier().getIsBsp() == FLIGHT_AUTO_TICKETING_BSP) {
        flightOrderService.updateFlightOrderSupplierType(enterpriseId, username, orderInfo.getId(), FLIGHT_AUTO_TICKETING_NDC_CZ);
        logger.info("{}: BSP -> NDC_CZ", orderInfo.getOrderNo());
        return 1;
      }
    }

    return 0;
  }

  @Override
  public JsonResult issueFlightOrderTicket(int enterpriseId, String username, int orderId) {
    //自动开票方式：BSP，接口
    final int etermApiType = doGetEntCfg(enterpriseId, TMS_AUTO_TICKET_MODE, 0);

    if (etermApiType == ETERM_API_DISABLED) {
      //停用自动开票
      return JsonResult.createJsonResult(-1, "自动开票已设置停用");
    }

    FlightOrder orderInfo = flightOrderDao.getOrderDetailById(orderId);

    if (!isValidToAutoTicketing(orderInfo)) {
      //不符合自动开票的条件
      return JsonResult.createJsonResult(-2, "不符合自动开票条件");
    }

    int orderChanged = prepareFlightOrder(enterpriseId, username, orderInfo);
    if (orderChanged == 1) {
      //刷新订单内容
      orderInfo = flightOrderDao.getOrderDetailById(orderInfo.getId());
    }

    int retCode = execAutoTicketOrder(enterpriseId, username, orderInfo, etermApiType, orderInfo.getSupplier().getIsBsp());

    return JsonResult.createJsonResult(retCode, "已执行自动开票");
  }


  /**
   * 检查机票订单是否符合自动开票条件
   * 自动开票的条件：
   * 国内机票，
   * 成人订单，
   * 单程或往返或两程，
   * 机票订单未设置非自动出票，
   * 机票订单的供应商是BSP或GP供应商，
   * 有成人票面价，
   */
  private boolean isValidToAutoTicketing(final FlightOrder flightOrder) {
    //不是国内票
    if (flightOrder.getIntlTicket() != 0) {
      return false;
    }

    // 不是单程,往返或双程
    if (flightOrder.getSegCount() > 2) {
      return false;
    }

    if (flightOrder.getAutoTicketing() == AUTO_PRINT_TICKET_NONE) {
      // 非自动开票
      return false;
    }

    if (flightOrder.getSupplier() == null) {
      //未设置供应商
      return false;
    }

    if (flightOrder.getSupplier().getIsBsp() != FLIGHT_AUTO_TICKETING_BSP
            && flightOrder.getSupplier().getIsBsp() != FLIGHT_AUTO_TICKETING_GP
            && flightOrder.getSupplier().getIsBsp() != FLIGHT_AUTO_TICKETING_NDC_CZ) {
      return false;
    }

    if (flightOrder.getPrice() < 1) {
      //没有成人票面价
      return false;
    }

    // 判断订单中的乘客是否全部为成人
    if (!FlightOrderUtil.isAdultFlightOrder(flightOrder)) {
      return false;
    }

    //判断现金订单是否已付款
    if (flightOrder.getPayType() == PAY_TYPE_CASH && flightOrder.getPayStatus() == PAY_STATUS_WAITING) {
      return false;
    }

    //查看客户是否测试模式
    if (isCustomerTestMode(flightOrder.getCustomer())) {
      logger.info("customer({}) is in test_mode.", flightOrder.getCustomerId());
      return false;
    }

    return true;
  }

  /**
   * 对机票订单进行自动出票操作
   * @param etermApiType 自动开票使用的接口类型
   * @param ticketingType 自动开票的类型：BSP(目前将南航NDC的开票算在此大类下面)，GP
   */
  private int execAutoTicketOrder(final int enterpriseId, final String username, final FlightOrder flightOrder,
                                   final int etermApiType, final int ticketingType) {
    // 判断是否设置自动开票
    if (flightOrder.getAutoTicketing() == AUTO_PRINT_TICKET_NONE) {
      return -1;
    }

    //标识认领开票是否成功
    boolean claimed = false;
    if (TmsOrderConstant.FLIGHT_ORDER_STATUS_WAIT_TICKETING == flightOrder.getStatus()) {
      //认领自动开票
      int retCode = autoClaimTicketing(enterpriseId, username, flightOrder, etermApiType, ticketingType);
      claimed = retCode == 1;
      if (!claimed) {
        logger.info("!claimed");
        return 0;
      }
    }

    if (TmsOrderConstant.FLIGHT_ORDER_STATUS_TICKETED == flightOrder.getStatus()) {
      logger.info("TmsOrderConstant.FLIGHT_ORDER_STATUS_TICKETED == flightOrder.getStatus()");
      return 0;
    }

    // 不是刚认领的，则判断开票人是否当前用户名
    if (!claimed && !username.equalsIgnoreCase(flightOrder.getTicketer())) {
      logger.info("!claimed && !username.equalsIgnoreCase(flightOrder.getTicketer())");
      return 0;
    }

    //2. 等待选择开票金额的，暂时不进入自动开票
    if (flightOrder.getAutoTicketing() == AUTO_PRINT_TICKET_PROCESSING
            && flightOrder.getAutoTicketingPrice() == 0) {
      // 等待选择PAT:A的金额（PAT:A的金额出现多个时，会发生此种情况）
      return 0;
    }

    //3. 首次等待开票的，进入开票状态；或等待PAT:A金额的，已经选择了金额
    int workerCount = 0;
    if (ticketingType == FLIGHT_AUTO_TICKETING_BSP) {
      if (etermApiType == ETERM_API_BUK) {
        //ETERM接口， BSP票
        etermWorker.autoTicketFlightOrder(enterpriseId, username, flightOrder.getId());
        workerCount++;
      } else if (etermApiType == ETERM_API_SZKJ) {
        //szkj 接口开票， BSP票
        szkjWorker.autoTicketFlightOrder(enterpriseId, username, flightOrder.getId());
        workerCount++;
      }
    } else if (ticketingType == FLIGHT_AUTO_TICKETING_GP) {
      //GP票
      gpWorker.autoTicketFlightOrder(enterpriseId, username, flightOrder.getId());
      workerCount++;
    } else if (ticketingType == FLIGHT_AUTO_TICKETING_NDC_CZ) {
      //BSP票, cz ndc 接口出票
      czNdcWorker.autoTicketFlightOrder(enterpriseId, username, flightOrder.getId());
      workerCount++;
    }

    return workerCount;
  }

  /**
   * 自动认领机票订单进行出票
   * @return 0: 认领失败
   *         1: 认领成功
   */
  private int autoClaimTicketing(final int enterpriseId, final String username, final FlightOrder flightOrder,
                                  final int etermApiType, final int ticketingType) {
    // 校验大客户政策开票是否符合年龄限制
    if (!isValidForAgeLimited(enterpriseId, username, flightOrder, 18, 65)) {
      //不符合年龄要求
      return 0;
    }

    //BSP开票（非GP）自动开票认领前，校验该编码是否已开票，如果已开票，则不进行自动开票操作
    if (etermApiType == ETERM_API_SZKJ && ticketingType == FLIGHT_AUTO_TICKETING_BSP) {
      //接口开票
      RtpnrResponse response = etermService.rt(enterpriseId, username, flightOrder.getPnrNo());
      if (response.getCode() == 1 && "1".equalsIgnoreCase(response.getPnrInfo().getIsEt())) {
        //接口调取成功，并且编码已开票，则退出自动开票
        int retCode = flightOrderDao.updateFlightOrderAutoTicketing(enterpriseId, username, flightOrder.getId(),
                AUTO_PRINT_TICKET_NONE, "编码已出票，停止自动出票流程。");
        if (retCode > 0) {
          doSendAlert(enterpriseId, flightOrder.getPnrNo() + "(" + flightOrder.getOrderNo() + ")已开票，需要人工处理", null, EntDepartment.DEPT_TICKETING);
        }

        return 0;
      }
    }

    //符合要求，认领该订单，并设置为自动出票
    int retCode = flightOrderDao.claimTicketingFlightOrder(enterpriseId, username, flightOrder.getId(), AUTO_PRINT_TICKET_WAITING);
    if (retCode > 0 && etermApiType == ETERM_API_SZKJ) {
      //认领成功，并且是接口开票， 提取编码保存开票前的编码内容
      try {
        doRefreshFlightOrderPnrDetail(enterpriseId, username, flightOrder.getId(), flightOrder.getOrderNo(), flightOrder.getPnrNo());
      } catch (Exception ex) {
        doSendAlert(enterpriseId, "认领自动开票后：(" + flightOrder.getPnrNo() + ")" + ex.getMessage(), "Dai", 0);
      }
    }

    return retCode;
  }


}
